package com.example.excel.annotation.helper;

import com.example.excel.annotation.Excel;
import com.example.excel.annotation.ExcelCell;
import com.example.excel.annotation.ExcelSheet;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

public interface OnHandlerExcelAnnotation {

        /**
         * 根据sheet的名称或者索引位置，获取可以读取的类
         *
         * @param sheetName
         * @param sheetIndex
         */
        Set<ExcelAnnotation> getReadSheetClass(int sheetIndex, String sheetName);

        OnHandlerExcelAnnotation parseAnnotation(Class... classes);

        void clear();


        static class Factory implements OnHandlerExcelAnnotation {

            private Map<String, Set<ExcelAnnotation>> sheetNameCache = new HashMap<>();
            private Map<Integer, Set<ExcelAnnotation>> sheetIndexCache = new HashMap<>();

            private static Map<Class, ExcelAnnotation[]> excelCache = new HashMap<>();

            public void setSheet(String sheetName, ExcelAnnotation excelAnnotation){
                Set<ExcelAnnotation> set = sheetNameCache.computeIfAbsent(sheetName, k -> new HashSet<>());
                set.add(excelAnnotation);
            }

            public void setSheet(int sheetIndex, ExcelAnnotation excelAnnotation){
                Set<ExcelAnnotation> set = sheetIndexCache.computeIfAbsent(sheetIndex, k -> new HashSet<>());
                set.add(excelAnnotation);
            }

            @Override
            public Set<ExcelAnnotation> getReadSheetClass(int sheetIndex, String sheetName) {
                Set<ExcelAnnotation> list = new HashSet<>();
                Set<ExcelAnnotation> tempList;
                tempList = sheetIndexCache.get(sheetIndex);
                if(tempList!=null && !tempList.isEmpty()){
                    list.addAll(tempList);
                }
                tempList = sheetNameCache.get(sheetName);
                if(tempList!=null && !tempList.isEmpty()){
                    list.addAll(tempList);
                }
                return list;
            }

            public OnHandlerExcelAnnotation parseAnnotation(Class... classes) {
                for (Class c : classes) {
                    ExcelAnnotation[] eas = excelCache.get(c);
                    if (eas == null) {
                        if (!c.isAnnotationPresent(Excel.class)) {
                            throw new IllegalArgumentException(c.getName() + " 必须使用@" + Excel.class.getSimpleName() + "注解！");
                        }
                        Map<Integer, Field> fieldMap = new HashMap<>();
                        Field[] fields = c.getDeclaredFields();
                        for (Field field : fields) {
                            if (field.isAnnotationPresent(ExcelCell.class)) {
                                ExcelCell excelCell = field.getAnnotation(ExcelCell.class);
                                fieldMap.put(excelCell.value(), field);
                            }
                        }
                        Excel excel =  (Excel) c.getAnnotation(Excel.class);
                        ExcelSheet[] excelSheet = excel.value();
                        eas = new ExcelAnnotation[excelSheet.length];
                        for (int i = 0; i < excelSheet.length; i++) {
                            ExcelSheet sheet = excelSheet[i];
                            ExcelAnnotation ea = new ExcelAnnotation();
                            ea.setaClass(c);
                            ea.setStartRow(sheet.startRow());
                            ea.setEndRow(sheet.endRow());
                            ea.setSheetIndex(sheet.sheetIndex());
                            ea.setSheetName(sheet.sheetNames());
                            ea.setColumns(fieldMap);
                            eas[i] = ea;
                            if(!ea.getSheetName().isEmpty()){
                                setSheet(ea.getSheetName(), ea);
                            }
                            else{
                                setSheet(ea.getSheetIndex(), ea);
                            }
                        }
                        excelCache.put(c, eas);
                    }
                }
                return this;
            }

            @Override
            public void clear() {
                sheetNameCache.clear();
                sheetIndexCache.clear();
                excelCache.clear();
            }
        }

    }